/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
* License for more details.
*
* $Id: ircsession.cpp 581 2009-05-19 16:40:38Z jpnurmi $
*/

#include "ircsession.h"
#include "ircsession_p.h"
#include "ircserverbuffer.h"
#include "ircchannelbuffer.h"
#include "ircbuffer.h"
#include <QTcpSocket>

namespace Irc
{
    /*!
        Constructs a new IRC session with \a parent.
     */
    Session::Session(QObject* parent) : QObject(parent), d_ptr(new SessionPrivate)
    {
        Q_D(Session);
        d->q_ptr = this;
        d->buffer.open(QIODevice::ReadWrite);
        setSocket(new QTcpSocket(this));
    }

    /*!
        Destructs the IRC session.
     */
    Session::~Session()
    {
        Q_D(Session);
        delete d;
    }

    /*!
        Returns the encoding.

        The default value is a null QByteArray.
     */
    QByteArray Session::encoding() const
    {
        Q_D(const Session);
        return d->encoding;
    }

    /*!
        Sets the \a encoding.

        See QTextCodec documentation for supported encodings.

        Encoding auto-detection can be turned on by passing a null QByteArray.

        The fallback locale is QTextCodec::codecForLocale().
     */
    void Session::setEncoding(const QByteArray& encoding)
    {
        Q_D(Session);
        d->encoding = encoding;
    }

    /*!
        Connects to server with \a host and \a port.
     */
    ServerBuffer* Session::connectToServer(const QString& host, quint16 port)
    {
        Q_D(Session);
        if (!d->socket || d->serverBuffer)
            return 0;

        d->socket->connectToHost(host, port);
        if (d->socket->inherits("QSslSocket"))
            QMetaObject::invokeMethod(d->socket, "startClientEncryption");

        d->serverBuffer = new ServerBuffer(host.toUtf8(), this);
        emit bufferAvailable(d->serverBuffer);
        return d->serverBuffer;
    }

    /*!
        Joins \a channel with optional \a key.
     */
    ChannelBuffer* Session::joinChannel(const QByteArray& channel, const QByteArray& key)
    {
        Q_D(Session);
        if (!d->socket || !d->serverBuffer)
            return 0;

        ChannelBuffer* buffer = new ChannelBuffer(channel, key, this);
        d->buffers[channel.toLower()] = buffer;
        emit bufferAvailable(buffer);
        return buffer;
    }

    /*!
        Opens a query with \a user.
     */
    Buffer* Session::openQuery(const QByteArray& user)
    {
        Q_D(Session);
        if (!d->socket || !d->serverBuffer)
            return 0;

        Buffer* buffer = new Buffer(user, this);
        d->buffers[user.toLower()] = buffer;
        emit bufferAvailable(buffer);
        return buffer;
    }

    /*!
        Returns a buffer for \name or the server buffer if null.
     */
    Buffer* Session::buffer(const QByteArray& name) const
    {
        Q_D(const Session);
        return d->buffers.value(name.toLower(), d->serverBuffer.data());
    }

    /*!
        Returns the socket.

        Irc::Session creates an instance of QTcpSocket by default.

        This function was introduced in version 0.3.0.
     */
    QAbstractSocket* Session::socket() const
    {
        Q_D(const Session);
        return d->socket;
    }

    /*!
        Sets the \a socket. The previously set socket is deleted if its parent is \c this.

        Irc::Session supports QSslSocket in the way that it automatically calls
        QSslSocket::startClientEncryption() while connecting.

        This function was introduced in version 0.3.0.
     */
    void Session::setSocket(QAbstractSocket* socket)
    {
        Q_D(Session);
        if (d->socket != socket)
        {
            if (d->socket)
            {
                d->socket->disconnect(this);
                if (d->socket->parent() == this)
                    d->socket->deleteLater();
            }

            if (socket)
            {
                connect(socket, SIGNAL(connected()), this, SLOT(_q_connected()));
                connect(socket, SIGNAL(disconnected()), this, SLOT(_q_disconnected()));
                connect(socket, SIGNAL(readyRead()), this, SLOT(_q_readData()));
                connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_error()));
                connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(_q_state()));
            }
            d->socket = socket;
        }
    }
}

#include "moc_ircsession.cpp"
